package com.demo.common.plugin.activerecord.directive;

import com.jfinal.plugin.activerecord.DbPro;
import com.jfinal.plugin.activerecord.SqlPara;
import com.jfinal.template.Directive;
import com.jfinal.template.Env;
import com.jfinal.template.TemplateException;
import com.jfinal.template.expr.ast.Expr;
import com.jfinal.template.expr.ast.ExprList;
import com.jfinal.template.expr.ast.Id;
import com.jfinal.template.io.CharWriter;
import com.jfinal.template.io.FastStringWriter;
import com.jfinal.template.io.Writer;
import com.jfinal.template.stat.Scope;

import java.io.IOException;

public abstract class SqlParaDirective extends Directive {
    protected Expr[] exprArray;
    protected String name;
    private Writer writer;

    //SqlKit.SQL_PARA_KEY
    protected static final String SQL_PARA_KEY = "_SQL_PARA_";
    private static final ThreadLocal<DbPro> TL = new ThreadLocal<>();

    @Override
    public void setExprList(ExprList exprList) {
        exprArray = exprList.getExprArray();
        if (exprArray.length == 0) {
            return;
        }
        if ((exprArray[0] instanceof Id)) {
            this.name = ((Id) exprArray[0]).getId();
        }
    }

    @Override
    public void exec(Env env, Scope scope, Writer writer) {
        this.writer = writer;
        SqlPara sqlPara = new SqlPara();
        //放入数据域中
        scope.setLocal(SQL_PARA_KEY, sqlPara);

        //渲染SQL
        CharWriter charWriter = new CharWriter(64);
        FastStringWriter fsw = new FastStringWriter();
        charWriter.init(fsw);
        try {
            stat.exec(env, scope, charWriter);
        } finally {
            charWriter.close();
        }

        //移除sqlPara对象，避免污染Map
        scope.removeLocal(SQL_PARA_KEY);
        sqlPara.setSql(fsw.toString());
        Object data = getData(sqlPara);
        //放置返回结果
        scope.set(name, data);
    }

    @Override
    public boolean hasEnd() {
        return true;
    }

    protected abstract Object getData(SqlPara sqlPara);

    protected void setDefaultName(String name) {
        if (this.name == null) {
            this.name = name;
        }
    }

    protected void write(String str) {
        try {
            writer.write(str, 0, str.length());
        } catch (IOException e) {
            throw new TemplateException(e.getMessage(), location, e);
        }
    }

    public static DbPro db(){
        return TL.get();
    }

    public static void setDb(DbPro db){
        TL.set(db);
    }

    public static void remove(){
        TL.remove();
    }
}
